package com.windowes.weichang.component.redis;

import com.google.gson.Gson;
import com.windowes.weichang.dto.WDistrictDto;
import com.windowes.weichang.pojo.WUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class RedisServiceImpl implements RedisService {

    @Autowired
    JedisPool jedisPool;

    /**
     * 设置key -value 形式数据
     *
     * @param key
     * @param value
     * @return
     */
    @Override
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.set(key, value);
        return result;
    }

    /**
     * 设置key -value 形式数据
     *
     * @param key
     * @param value
     * @return
     */
    @Override
    public String setEx(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.set(key, value);
        return result;
    }

    @Override
    public String get(String key) {
        Jedis jedis = jedisPool.getResource();
        return jedis.get(key);
    }


    /**
     * 判断key是否存在
     */
    @Override
    public <T> boolean exists(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.exists(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    @Override
    public boolean exists(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            return jedis.exists(key);
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 删除
     */
    @Override
    public boolean delete(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            long ret = jedis.del(realKey);
            return ret > 0;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 增加值
     */
    @Override
    public <T> Long incr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.incr(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 减少值
     */
    @Override
    public <T> Long decr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            return jedis.decr(realKey);
        } finally {
            returnToPool(jedis);
        }
    }

    @Override
    public boolean delete(KeyPrefix prefix) {
        if (prefix == null) {
            return false;
        }
        List<String> keys = scanKeys(prefix.getPrefix());
        if (keys == null || keys.size() <= 0) {
            return true;
        }
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.del(keys.toArray(new String[0]));
            return true;
        } catch (final Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    @Override
    public List<String> scanKeys(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            List<String> keys = new ArrayList<String>();
            String cursor = "0";
            ScanParams sp = new ScanParams();
            sp.match("*" + key + "*");
            sp.count(100);
            do {
                ScanResult<String> ret = jedis.scan(cursor, sp);
                List<String> result = ret.getResult();
                if (result != null && result.size() > 0) {
                    keys.addAll(result);
                }
                //再处理cursor
                cursor = ret.getStringCursor();
            } while (!cursor.equals("0"));
            return keys;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    @Override
    public void setUser(String token, WUser user) {
        long loginExpire = 7 * 24 * 60 * 60;
        saveExpxKeyCache(token, new Gson().toJson(user), loginExpire);
    }

    @Override
    public boolean deleteByKey(String key) {

        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            if (jedis.exists(key)) {
                jedis.del(key);
            }

            return true;
        } catch (final Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    @Override
    public WUser getUser(String token) {
        return new Gson().fromJson(get(token), WUser.class);
    }

    @Override
    public List<WDistrictDto> getDistrict(Integer id) {
        String districts = get("district:" + id);
        if (StringUtils.isBlank(districts)) {
            return null;
        }
        return Arrays.asList(new Gson().fromJson(districts, WDistrictDto[].class));
    }

    @Override
    public void setDistrict(Integer id, List<WDistrictDto> districts) {
        set("district:" + id, new Gson().toJson(districts));
    }


    private void returnToPool(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }


    /***
     * Only set the key if it does not already exist
     *
     * @param k
     * @param v
     * @param time : second
     */
    @Override
    public void saveExpxKeyCache(String k, String v, long time) {
        saveExpxKeyCache(k, v, "NX", time);
    }

    @Override
    public void subscribe(JedisPubSub jedisPubSub, String... channels) {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.subscribe(jedisPubSub, channels);
        } catch (Exception e) {
            e.printStackTrace();
            jedis = null;
        } finally {
            if (jedis != null) {
                returnToPool(jedis);
            }
        }
    }


    /***
     * @param k
     * @param v
     * @param nxxx :  NX|XX, NX -- Only set the key if it does not already exist. XX -- Only set the key
     *             if it already exist.
     * @param time : second
     */
    public void saveExpxKeyCache(String k, String v, String nxxx, long time) {
        Jedis jedis = jedisPool.getResource();
        try {
            Boolean exists = jedis.exists(k);
            if (exists) {
                jedis.del(k);
            }
            jedis.set(k, v, nxxx, "EX"/*seconds*/, time);
        } catch (Exception e) {
            e.printStackTrace();
            jedis = null;
        } finally {
            if (jedis != null) {
                returnToPool(jedis);
            }
        }

    }
}
